/**
 * Project 68th
 */


#include "ThreadPool.h"

/**
 * ThreadPool implementation
 */


/**
 * @param threadNum
 * @param queSize
 */
ThreadPool::ThreadPool(size_t threadNum, size_t queSize) 
: _threadNum(threadNum)
, _threads()
, _queSize(queSize)
, _taskQue(_queSize)
, _isExit(false)
{

}

ThreadPool::~ThreadPool() {

}

/**
 * @return void
 */
void ThreadPool::start() {
    //线程池启动，就创建子线程
    //将关联子线程的thread对象放到vector中
    for(size_t idx = 0; idx < _threadNum; ++idx)
    {
        //由于thread是不能进行复制的
        //所以push_back给vector增加元素时必须要
        //采用移动语义
        /* thread th(&ThreadPool::doTask,this); */
        /* _threads.push_back(std::move(th)); */

        _threads.push_back(thread(&ThreadPool::doTask,this));
    }
}

/**
 * @return void
 */
void ThreadPool::stop() {
    //如果任务队列不为空，就让主线程等待
    while(!_taskQue.empty())
    {
        /* sleep(1); */
        //C++11提供的写法
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    //标志位改成true，意味着线程池要退出
    _isExit = true;

    //如果子线程都在wait，那么join无法正常地回收资源
    //所以应该在join之前唤醒wait的子线程
    //
    //将ThreadPool设为TaskQueue的友元
    /* _taskQue._notEmpty.notify_all(); */

    _taskQue.wakeup();


    for(auto & th: _threads)
    {
        th.join();
    }
}

/**
 * @param ptask
 * @return void
 */
void ThreadPool::addTask(ElemType && ptask) {
    if(ptask)
    {
        _taskQue.push(std::move(ptask));
    }
}

/**
 * @return ElemType
 */
ElemType ThreadPool::getTask() {
    return _taskQue.pop();
}

/**
 * @return void
 */
void ThreadPool::doTask() {
    //只要线程池不退出，就让工作线程一直执行任务
    //如果任务队列为空，就让工作线程阻塞
    //
    //问题一：任务添加完毕，但是没有执行足够数量的任务
    //程序就退出了
    //原因：主线程执行stop会将_isExit标志位直接改为true
    //子线程在执行doTask的过程中，
    //可能并没有执行足够次数的循环
    //
    //问题二：任务确实执行了20次，但是程序无法正常退出
    //分析原因应该是pop函数导致了子线程阻塞
    //主线程等待1秒的期间，子线程将任务队列中剩余的任务
    //全部执行完毕，然后又进入了doTask中的while循环
    //此时调用getTask，内部调用TaskQueue的pop函数
    //由于任务队列为空，所以所有的子线程都在
    //条件变量_notEmpty上wait
    while(!_isExit)
    {
        ElemType ptask = getTask();

        if(ptask)
        {
            //基于对象的多态
            ptask();

            //只是为了验证，不要真的这么干
            //如果子线程每次执行任务都至少需要3秒
            //那么就不会在主线程等待1秒的时间内将
            //所有剩余的任务都执行完，然后卡在pop中
            /* sleep(3); */
        }
        else
        {
            cout << "ptask是空的function" << endl;
        }
    }

}
